<?php
/*
 |------------------------------------------------------------------------------
 | vendor Model
 |------------------------------------------------------------------------------
 |
 | Time: 2017-10-11  15:20
 |
 | Describe: 基础model
 |  
 */

namespace Jason\Db;
class Model
{
    public $config;
    public $table;
    public $table_status  = [];
    private static $db;
    public function __construct()
    {
        $this->init();
    }
    public function init(){}

    private function db()
    {
        if(!isset(self::$db[$this->config['type']])) {
            self::$db[$this->config['type']] = Db::connect($this->config,$this->config['type']);
        }
        return self::$db[$this->config['type']];
    }
    public function getDb()
    {
        return $this->db();
    }
    /**
     * 增加数据
     *   - 支持单条SQL语句，$row 需要为字符串型,$row必须是完整的sql语句，后台验证insert
     *   - 如果是sql
     *   - 只返回成功以否，不返回插入的自增ID
     *
     * @param string|array() $row  需要增加的表字段
     * @param string $table
     * @return int - 更新影响的行数 | false
     * 形式一：add(['title'=>'标题']) 推荐
     * 形式二：add('INSERT INTO `test`.`ac` (`id`, `title`) VALUES (1, 'FSDF');')，不推荐，用不上预处理
     */
    protected function add($row, $replace = false, $table='')
    {
        if (! $table){
            $table = $this->table;
        }

        if (is_array($row)){
            if (! $this->_encodeTableRow($row)){
                $error = '[ADD_DIFF] 添加字段与表字段不匹配';
                $this->db()->write($error);
                return false;
            }
            $result = $this->db()->insert($table, $row, $replace);
        } else {
            $result = $this->db()->insertBySql($row);
        }
        return $result;
    }

    /**
     * 增加数据(获取自增ID)
     *   - 支持单条SQL语句，$row 需要为字符串型,$row必须是完整的sql语句，后台验证insert
     *   - 如果是sql
     *   - 只返回成功以否，不返回插入的自增ID
     *
     * @param string|array() $row  需要增加的表字段
     * @param string $table
     * @return int - 更新影响的行数 | false
     * 形式一：addGetInsertId(['title'=>'标题'])
     * 形式二：addGetInsertId('INSERT INTO `test`.`ac` (`id`, `title`) VALUES (1, 'FSDF');')，不推荐，用不上预处理
     */
    protected function addGetInsertId($row, $replace = false, $table='')
    {
        if (! $table){
            $table = $this->table;
        }
        if (is_array($row)){
            if (! $this->_encodeTableRow($row)){
                $error = '[ADD_DIFF] 添加字段与表字段不匹配';
                $this->db()->write($error);
                return false;
            }
            $result = $this->db()->insert($table, $row, $replace, TRUE);
        } else {
            $result = $this->db()->insertBySql($row, TRUE);
        }
        return $result;
    }

    /**
     * 更新操作
     * @param string|array $row
     * @param string $where
     * @param string $table
     * @return boolean|unknown  返回受影响的行数
     * 形式一：update(['title'=>'标题'], 'id=1')，不推荐，用不上预处理
     * 形式二：update(['title'=>'标题'], ['id'=>1])
     * 形式三：update('UPDATE user SET name = xxx WHERE id = 1')，不推荐，用不上预处理
     * 形式四：update('UPDATE user SET name = ? WHERE id = ?', ['xxx', '1'])
     */
    protected function update($row, $where = '', $table=''){
        if (! $table){
            $table = $this->table;
        }
        if (is_array($row)){
            if (! $this->_encodeTableRow($row)){
                $error = '[ADD_DIFF] 添加字段与表字段不匹配';
                $this->db()->write($error);
                return false;
            }
            $result = $this->db()->update($table, $row, $where);
        } else {
            // 当$row是一条sql时，where参数作为绑定数组，见形式四
            $bindArr = is_array($where) ? $where : [];
            $result = $this->db()->updateBySql($row, $bindArr);
        }
        return $result;
    }

    /**
     * 删除数据，返回受影响的行数
     * @param unknown $where
     * @param string $table
     * 形式一：delete(['id'=>1])
     * 形式二：delete('id=1')，不推荐，用不上预处理
     */
    protected function delete($where, $table=''){

        if (! $where) {
            $error = ' [SELECT_WHERE] 查询缺少 WHERE 条件 ';
            $this->db()->write($error);
            return false;
        }

        if (! $table){
            $table = $this->table;
        }

        $result = $this->db()->delete($table, $where);
        return $result;
    }

    /**
     * 获取单条数据
     * @param unknown $where
     * @param unknown $fields
     * @param string $order
     * @param string $table
     * 形式一：getRow(['id'=>'1'])
     * 形式二：getRow('id=1')，不推荐，用不上预处理
     */
    protected function getRow($where, $fields = array(), $order = null, $table = null,  $master = false){
        if (! $where) {
            $error = ' [SELECT_WHERE] 查询缺少 WHERE 条件 ';
            $this->db()->write($error);
            return array();
        }

        if (! $table){
            $table = $this->table;
        }

        $result = $this->db()->selectOne($table, $where, $fields, $order, $master);

        if (false === $result){
            return array();
        }

        $this->_decodeTableRow($result);

        return $result;
    }

    /**
     * 获取多条数据
     * @param unknown $where
     * @param unknown $fields
     * @param string $order
     * @param string $limit
     * @param string $table
     * 形式一：getRows(['id'=>'1'])
     * 形式二：getRows('id=1')，不推荐，用不上预处理
     */
    protected function getRows($where, $fields = array(), $order = null, $limit = null, $table = null,  $master = false){
        if (! $where) {
            $error = ' [SELECT_WHERE] 查询缺少 WHERE 条件 ';
            $this->db()->write($error);
            return array();
        }

        if (! $table){
            $table = $this->table;
        }

        $result = $this->db()->selectAll($table, $where, $fields, $order, $limit, $master);

        if (false === $result){
            return array();
        }

        foreach ($result as &$row) {
            $this->_decodeTableRow($row);
        }
        unset($row);

        return $result;
    }

    /**
     * 按照sql获取数据
     * @param unknown $sql
     * @param boolean $master 是否从主库获取
     * @param array $bindArr 临时新增预处理绑定值数组
     * 形式：(select id,name where table where id=?, ['123'])
     * @return array
     */
    protected function getRowsBySql($sql, $bindArr = [] ,$master = false) {
        if (empty($sql)) {
            $error = ' [SELECT] 查询缺少 sql 条件 ';
            $this->db()->write($error);
            return array();
        }

        $result = $this->db()->setlectBySql($sql, $bindArr, $master);

        if (false === $result) {

            return array();
        }

        foreach ($result as &$row) {
            $this->_decodeTableRow($row);
        }
        unset($row);

        return $result;
    }

    /**
     * 按照sql获取单条数据
     * @param unknown $sql
     * @param string $master
     * @param array $bindArr 临时新增预处理绑定值数组
     * 形式：(select id,name where table where id=?, ['123'])
     * @return array
     */
    protected function getRowBySql($sql, $bindArr = [], $master = false) {
        $result = $this->getRowsBySql($sql, $bindArr, $master);

        if (empty($result)) {
            return array();
        }

        return $result[0];
    }
    protected function getLastSql()
    {
        return $this->db()->getLastSql();
    }
    /*========================================================================*/
    /**
     * 解析数据库语句
     *
     * @param array() $row
     * @return bool
     */
    private function _encodeTableRow(&$row)
    {
        if (! $this->table_status || ! $row){
            return true;
        }
        foreach ($row as $k=>$v){
            if (! isset($this->table_status[$k])){
                return false;
            }

            if ($this->table_status[$k] == 'i'){
                $row[$k] = $v+0;
            }
            elseif ($this->table_status[$k] == 's'){
                $row[$k] = $v . '';
            }
            elseif ($this->table_status[$k] == 'x'){
                if (! is_array($v)){
                    return false;
                }
                $row[$k] = json_encode($v);
            }
        }

        return true;
    }

    /**
     * 解析从数据库中获取的数据
     *     - 需要配置$table_status 变量，该变量定义了
     *
     * @param array() $row
     * @return array()
     */
    private function _decodeTableRow(&$row)
    {
        if (! $this->table_status || ! is_array($row) || ! $row){
            return true;
        }
        foreach ($row as $k=>$v){
            $type = isset($this->table_status[$k]) ? $this->table_status[$k] : '';
            if ($type)
            {
                if ($this->table_status[$k] == 'x'){
                    if (! $v){
                        $row[$k] = array();
                    }
                    else{
                        $row[$k] = json_decode($v, true);
                    }
                }
            }
        }

        return true;
    }
}
